package com.borya.service.mobile.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.borya.constant.RedisConstant;
import com.borya.dao.ProConfDAO;
import com.borya.dao.SdkAppDao;
import com.borya.dao.TencentDAO;
import com.borya.dao.UserDAO;
import com.borya.framework.annotation.Autowired;
import com.borya.framework.annotation.Component;
import com.borya.framework.core.ServerRequest;
import com.borya.framework.util.ObjectUtils;
import com.borya.model.db.*;
import com.borya.model.entity.FaceIdResponse;
import com.borya.model.entity.HeaderEntity;
import com.borya.model.entity.SmsInfo;
import com.borya.model.entity.UserToken;
import com.borya.service.mobile.SdkAppService;
import com.borya.statuscode.StatusCode;
import com.borya.util.*;
import com.borya.util.cipher.EncryptUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.util.TextUtils;
import org.apache.log4j.Logger;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Clock;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Component("sdkAppServiceImpl")
public class SdkAppServiceImpl implements SdkAppService {

    public Logger log = Logger.getLogger(getClass());

    private static final Map<String, SmsInfo> SMC_CODE_MAP = new HashMap<>();
    private static final long SMS_TIMEOUT = Constant.SMS_TIMEOUT;
    private final static String TENCENT_URL = "https://idasc.webank.com";
    private final static String NONCE_TICKET = "/api/oauth2/api_ticket?app_id=%s&access_token=%s&type=NONCE&version=1.0.0&user_id=%s";
    private final static String ACCESS_TOKEN_URL = "/api/oauth2/access_token?app_id=%s&secret=%s&grant_type=client_credential&version=1.0.0";
    private final static String FACEID_URL = "/api/server/getfaceid";

    @Autowired("sdkAppDaoImpl")
    private SdkAppDao sdkAppDao;
    @Autowired("userDAOImpl")
    private UserDAO userDAO;
    @Autowired("proConfDAOImpl")
    private ProConfDAO proConfDAO;
    @Autowired("tencentDAOImpl")
    private TencentDAO tencentDAO;

    @Override
    public String getLoginCode(JSONObject json,ServerRequest request) {
        UserToken ut = (UserToken)request.getAttribute("userToken");
        User user = (User)request.getAttribute("user");
        String appId = ut.getAppId();
        if(StringUtils.isEmpty(appId)){
            return StatusCode.PARAM_ERROR.toJSON("非法请求");
        }
        //detailType = getDetailTypeByAppId(appId);
        int detailType = user.getDetailType();
        if(ObjectUtils.isNull(detailType)){
            return StatusCode.PARAM_ERROR.toJSON("非法请求");
        }
        final String phoneNumber = json.getString("userPhone");

        String userId = user.getUserId();
        final String osType = ut.getOsType();
        if (TextUtils.isBlank(phoneNumber)) {
            log.warn("参数 phone 不能为空");
            return StatusCode.PARAM_ERROR.toJSON("参数不能为空");
        }
        final String phone = phoneNumber.replaceAll(" ", "");
        if (phone.length() != 11) {
            log.warn("参数 phone 长度错误");
            return StatusCode.PARAM_ERROR.toJSON();
        }
        if (StringUtils.isBlank(osType) || !"1,2".contains(osType)) {
            log.warn("osType参数错误,osType=" + osType);
            return StatusCode.PARAM_ERROR.toJSON();
        }
        if (user == null) {
            log.warn(String.format("单点结算SDK系统用户: %s 未注册签约", phone));
            return StatusCode.USER_NOT_FOUND.toJSON("您还未签约，请先完成签约");
        }
        if(StringUtils.isEmpty(userId)){
            log.warn(String.format("单点结算SDK系统用户: %s 未注册签约", phone));
            return StatusCode.USER_NOT_FOUND.toJSON("您还未激活，请先完成激活");
        }

        if (user.getFlag() == com.borya.model.db.Flag.DELETED) {
            log.warn("手机号为:" + phone + " 的用户已被删除");
            return StatusCode.USER_NOT_FOUND.toJSON("用户未注册");
        }
        if(1 == detailType){
            if (user.getSourceType() == 2) {
                // 远特时空用户
                log.warn("用户:" + user.getUserId() + " 为远特时空用户");
                return StatusCode.USER_NOT_FOUND.toJSON("该号码非卡盟账号！");
            }
        }

        Merchant merchant = userDAO.getMerchant(user.getDealerId());
        String result = processFlag(merchant);
        if (result != null) {
            return result;
        }
        Boolean blackFlag = userDAO.checkBlackUser(user.getUserId());
        if (blackFlag == null) {
            log.warn("查询黑名单返回null");
            return StatusCode.SYSTEM_EXCEPTION.toJSON();
        }
        if (blackFlag) {
            log.warn("黑名单用户,userid:" + user.getUserId());
            return StatusCode.USER_NOT_FOUND.toJSON("您已被加入黑名单，解封请联系管理员");
        }

        return process_sms(user.getUserId(),phone,osType,detailType);
    }

    private String process_sms(String userId, String phone, String osType, Integer detailType) {
        final long curTime = System.currentTimeMillis();
        SmsInfo smsInfo = SMC_CODE_MAP.get(detailType + userId);
        // 短信内容不存在，或者超时了，重新发送
        if (smsInfo == null || smsInfo.getTimeoutTime() < curTime) {
            String authCode = StringUtil.randomNumberString(6);
            if (Constant.IS_TEST) {
                authCode = "666666";
                log.info("测试环境，验证码写死");
            }
            String content = "尊敬的用户,您本次的短信动态码为:" + authCode + "，如非本人操作,请忽略本次通知。";
            boolean ok = sendMsg(phone, content);
            if (ok) {
                SmsInfo smsInfo2 = new SmsInfo();
                smsInfo2.setAuthCode(authCode);
                smsInfo2.setTimeoutTime(curTime + SMS_TIMEOUT);
                smsInfo2.setRequesttype(osType);

                SMC_CODE_MAP.put(detailType + userId, smsInfo2);
                log.info("[SdkApp] 向用户:" + phone + "发送短信验证码成功");
                return StatusCode.SUCCESS.toJSON();
            } else {
                log.info("[SdkApp] 向用户：" + phone + "发送短信验证码失败");
                return StatusCode.SYSTEM_EXCEPTION.toJSON("获取短信验证码失败，请稍后再试");
            }
        } else {
            log.info("[SdkApp] 短信验证码已向用户：" + phone + "发送出去了");
            return StatusCode.SUCCESS.toJSON("您的短信验证码已经发送到你手机上了，请注意查收");
        }
    }

    private boolean sendMsg(String phone, String content) {
        log.info(phone + content);
        return SmsUtils.sendMsg(phone, content);
    }

    private String processFlag(Merchant merchant) {
        if (merchant == null) {
            log.warn("商户:" + merchant + " 未注册");
            return StatusCode.USER_NOT_FOUND.toJSON("您还未注册，请点击“创建账号”快来注册！");
        }
        if (merchant.getDealerId() == null || merchant.getDealerId().trim().length() == 0) {
            log.warn("商户:" + merchant + " 未注册");
            return StatusCode.USER_NOT_FOUND.toJSON("您还未注册，请点击“创建账号”快来注册！");
        }
        switch (merchant.getFlag()) {
            case Merchant.Flag.WRITE_OFF:
                log.warn("商户已注销," + merchant);
                return StatusCode.USER_NOT_FOUND.toJSON("您所在商户已被注销,具体请联系管理员！");
            default:
                break;
        }
        return null;
    }

    @Override
    public String login(JSONObject json,ServerRequest request) {
        String detailType = null;
        //String appId = json.getString("userToken");
        UserToken ut = (UserToken)request.getAttribute("userToken");
        String appId = ut.getAppId();
        if(StringUtils.isEmpty(appId)){
            return StatusCode.PARAM_ERROR.toJSON("非法请求");
        }
        HeaderEntity authHeader = (HeaderEntity) request.getAttribute("boryaAuth");
        User user = (User) request.getAttribute("user");
        if("1".equals(detailType)){
            //卡盟侧login
            return kamengLogin(json);
        }else{
            //单点结算侧login
            return dandianLogin(json,authHeader,ut,user);
        }
    }

    @Override
    public String livingPre(JSONObject json, ServerRequest request) {
        User user = (User) request.getAttribute("user");
        HeaderEntity authHeader = (HeaderEntity) request.getAttribute("boryaAuth");
        String userId = user.getUserId();
        Optional<UserClientDetail> opt = sdkAppDao.getUserClientDetailByUser(userId);
        UserClientDetail userClientDetail = null;
        if(opt.isPresent()){
            userClientDetail = opt.get();
        }else{
            return StatusCode.USER_NOT_FOUND.toJSON("用户不存在");
        }
        Integer livingStatus = userClientDetail.getLivingStatus();
        String idNo = userClientDetail.getIdentityCard();
        String identityCardName = userClientDetail.getIdentityCardName();
        String photoHandImgUrl = userClientDetail.getIdentifyPhotoHand();
        String photoHeadImgUrl = userClientDetail.getIdentifyPhotoHead();
        if(ObjectUtils.isNullOrEmpty(identityCardName)
                || ObjectUtils.isNullOrEmpty(idNo)
                || Objects.isNull(photoHandImgUrl)){
            log.warn(String.format("param error,name:%s,idNo:%s,photoHandImgUrl:%s;",identityCardName,idNo,photoHandImgUrl));
            return StatusCode.PARAM_ERROR.toJSON("用户参数不存在");
        }
        log.info(String.format("userid:%s，活体识别参数,name:%s,idNo:%s,photoHandImgUrl:%s;",userId,identityCardName,idNo,photoHandImgUrl));
        String replace = photoHandImgUrl.replace("_narrow.png", ".png");
        //String imgurlTemp = String.format(Constant.OssInfo.END_POINT_FORMAT, Constant.OssInfo.OSS_BACKET_NAME + ".") + "/" + replace;
        String imgurlTemp = String.format(Constant.OssInfo.END_POINT_FORMAT, Constant.OssInfo.OSS_BACKET_NAME + ".") + "/" + photoHeadImgUrl;
        String imgUrl = AliOSSUtil.generatePresignedUrl(300, imgurlTemp);

        String sysOrderId = StringUtil.createSysOrderPayId();

        String packageName = authHeader.getPackageName();
        if(StringUtils.isEmpty(packageName)){
            return StatusCode.PARAM_ERROR.toJSON("包名不存在");
        }

        TencentLivingConf livingConf = tencentDAO.getConf(packageName);
        if(Objects.isNull(livingConf)){
            log.warn(packageName +"：腾讯云活体识别配置文件出错");
            return StatusCode.SYSTEM_EXCEPTION.toJSON(packageName +"：腾讯云配置文件出错");
        }
        FaceIdResponse response = new FaceIdResponse();
        response.setNonce(StringUtil.randomString(32));
        response.setAppid(livingConf.getAppid());
        response.setOrderNo(sysOrderId);
        response.setApiVersion(Constant.Tencent.APIVERSION);
        response.setUserId(userId);

        try {
            final String ticKet = getNonceTicket(userId,livingConf);
            if(Objects.isNull(ticKet)){
                return StatusCode.SYSTEM_CONFIG_ERROR.toJSON("系统配置错误");
            }
            if(livingStatus.equals(1)){
                //无源
                response.setSign(sign(response.getSignList(userId),ticKet));
                response.setLicence(livingConf.getLicense());
                response.setFacetype(String.valueOf(livingConf.getFaceType()));
                response.setActive(livingStatus+"");
                response.setImgScore(Integer.valueOf(Constant.OssInfo.SDK_APP_IMG_SCORE));
                setFaceId(identityCardName,idNo,userId,response,imgUrl);
            }else{
                //3:有源(2是不做，在获取登录方式的时候，已经返回用短信登录了)
                response.setSign(sign(response.getSignList(userId),ticKet));
                response.setLicence(livingConf.getLicense());
                response.setFacetype(String.valueOf(livingConf.getFaceType()));
                response.setActive(livingStatus+"");
                response.setImgScore(Integer.valueOf(Constant.OssInfo.SDK_APP_IMG_SCORE));
                setFaceId(identityCardName,idNo,userId,response,"");
            }

            /**添加预提交记录**/
            LivingPreLog livingPreLog = new LivingPreLog();
            livingPreLog.setSysOrderId(sysOrderId);
            livingPreLog.setCheckOrderId(response.getOrderNo());
            livingPreLog.setFaceId(response.getFaceId());
            tencentDAO.addLivingPreLog(livingPreLog);
            log.info("活体识别/c/tencent/livingPre返回参数："+JSON.toJSONString(response));
            return StatusCode.SUCCESS.toDiyJson("data",(JSONObject)JSON.toJSON(response));
        } catch (Exception e) {
            log.error(e.getMessage(),e);
            return StatusCode.SYSTEM_EXCEPTION.toJSON(e.getMessage());
        }
    }

    private void setFaceId(String name,String idNo,
                           String userId,FaceIdResponse response,String imgUrl) throws Exception{
        JSONObject body = new JSONObject();
        body.put("webankAppId",response.getAppid());
        body.put("orderNo",response.getOrderNo());
        body.put("name",name);
        body.put("idNo",idNo);
        body.put("userId",userId);
        body.put("sourcePhotoType",2);
        body.put("version",response.getApiVersion());
        body.put("sign",response.getSign());
        if(ObjectUtils.nonNullOrEmpty(imgUrl)){
            //传了照片 先获取base64，成功的话传无源
            String base64Str = HTTPUtils.sendGetReBase64Str(imgUrl);
            if(Objects.nonNull(base64Str)
                    && base64Str.length() < 1048576){
                body.put("sourcePhotoStr",base64Str);
                body.put("name","");
                body.put("idNo","");
            }
        }
        log.info(String.format("%s,给腾讯传参idNo:%s，收到imgName:%s",response.getOrderNo(),
                body.getString("idNo"),imgUrl));
        final String url = TENCENT_URL + FACEID_URL;
        String result = HTTPUtils.sendPostJSON(url,body.toJSONString());
        if(ObjectUtils.isNullOrEmpty(result)){
            throw new Exception("获取FaceId失败，请稍后再试");
        }
        JSONObject resJson = JSONObject.parseObject(result);
        if(! Objects.equals("0",resJson.getString("code"))){
            log.warn(String.format("获取faceId失败,url【%s】body【%s】result【%s】",
                    url,body,result));
            throw new Exception(resJson.getString("msg"));
        }
        final String faceId = resJson.getJSONObject("result").getString("faceId");
        response.setFaceId(faceId);
    }

    private String sign(List<String> values, String ticket) {
        if (values == null) {
            throw new NullPointerException("values is null");
        }
        values.removeAll(Collections.singleton(null));// remove null
        values.add(ticket);
        java.util.Collections.sort(values);

        StringBuilder sb = new StringBuilder();
        for (String s : values) {
            sb.append(s);
        }
        return shaEncode(sb.toString()).toUpperCase();
    }

    /**
     * @Comment SHA1实现
     * @Author Ron
     * @Date 2017年9月13日 下午3:30:36
     * @return
     */
    private String shaEncode(String inStr) {
        try {
            MessageDigest sha =  MessageDigest.getInstance("SHA");
            byte[] byteArray = inStr.getBytes("UTF-8");
            byte[] md5Bytes = sha.digest(byteArray);
            StringBuffer hexValue = new StringBuffer();
            for (int i = 0; i < md5Bytes.length; i++) {
                int val = ((int) md5Bytes[i]) & 0xff;
                if (val < 16) {
                    hexValue.append("0");
                }
                hexValue.append(Integer.toHexString(val));
            }
            return hexValue.toString();
        } catch (UnsupportedEncodingException e1){
            log.error(e1.getMessage(),e1);
        } catch (NoSuchAlgorithmException e2){
            log.error(e2.getMessage(),e2);
        }
        return null;
    }

    private String getNonceTicket(String userId, TencentLivingConf conf) throws Exception{
        final String accessToken = getToken(conf);
        if(Objects.isNull(accessToken)){
            return null;
        }
        String url = String.format(TENCENT_URL + NONCE_TICKET,
                conf.getAppid(),accessToken,userId);
        String result = HTTPUtils.sendGet(url);
        log.info(String.format("getNonceTicket URL【%s】result【%s】",url,result));
        if(Objects.isNull(result)){
            log.error("腾讯云获取ticket返回null,"+url);
            return null;
        }
        JSONObject json = JSONObject.parseObject(result);
        if(!Objects.equals("0",json.getString("code"))){
            log.error("腾讯云获取ticket失败，"+result);
            throw new Exception(json.getString("msg"));
        }
        return json.getJSONArray("tickets").getJSONObject(0).getString("value");
    }

    private String getToken(TencentLivingConf conf) throws Exception{
        final String key = Constant.Tencent.ACCESS_TOKEN_KEY + conf.getRedisSpace();
        final String runnungKey = key + ":ing";
        /**判断是否有更新中请求**/
        for (;;){
            if(tencentDAO.redis_ttl(runnungKey) < 0)
                break;
        }
        final long tokenttl = tencentDAO.redis_ttl(key);
        if(tokenttl > 60){
            return tencentDAO.redis_get(key);
        }
        /**access_token 更新的时候 将缓存的signticket删除**/
        tencentDAO.redis_del(Constant.Tencent.SIGN_TICKET_KEY + conf.getRedisSpace());
        /**access_token 更新的时候 将缓存的signticket删除**/
        tencentDAO.redis_set(runnungKey,"1");
        tencentDAO.redis_expire(runnungKey,60);
        String url = String.format(TENCENT_URL + ACCESS_TOKEN_URL,
                conf.getAppid(),conf.getAppkey());
        String result = HTTPUtils.sendGet(url);
        if(Objects.isNull(result)){
            log.error("腾讯云获取accessToken返回null,"+url);
            tencentDAO.redis_del(runnungKey);
            return null;
        }
        JSONObject json = JSONObject.parseObject(result);
        if(!Objects.equals("0",json.getString("code"))){
            log.error("腾讯云获取accessToken失败，"+result);
            tencentDAO.redis_del(runnungKey);
            throw new Exception(json.getString("msg"));
        }
        String accessToken = json.getString("access_token");
        tencentDAO.redis_set(key,accessToken);
        tencentDAO.redis_expire(key,Constant.Tencent.ACCESS_TOKEN_KEY_TIME);
        tencentDAO.redis_del(runnungKey);
        return accessToken;
    }

    private String getLivingCheckFlagByAppId(String appId) {
        String result = sdkAppDao.redis_get(RedisConstant.SDK_APP_CONF_KEY);
        JSONObject sdkAppConfObj ;
        if(StringUtils.isEmpty(result)){
            //redis无，查询数据库，再存入redis
             sdkAppConfObj = sdkAppDao.getLivingCheckFlagInfo();
            if(ObjectUtils.isNullOrEmpty(sdkAppConfObj)){
                return null;
            }else{
                sdkAppDao.redis_set(RedisConstant.SDK_APP_CONF_KEY, JSON.toJSONString(sdkAppConfObj));
                sdkAppDao.redis_expire(RedisConstant.SDK_APP_CONF_KEY,10 * 60);
                String livingCheckFlag = sdkAppConfObj.getString(appId);
                if(StringUtils.isNotEmpty(livingCheckFlag)){
                    return livingCheckFlag;
                }else{
                    return null;
                }
            }
        }else{
            //redis有值，直接取detailType
            sdkAppConfObj = JSON.parseObject(result);
            String livingCheckFlag = sdkAppConfObj.getString(appId);
            if(StringUtils.isNotEmpty(livingCheckFlag)){
                return livingCheckFlag;
            }else{
                return null;
            }
        }
    }

    private String dandianLogin(JSONObject json,HeaderEntity authHeader,UserToken ut,User user) {
        try {
            // Deprecated 兼容老版本
            final String userId = user.getUserId();
            final String authCode = json.getString("authCode");
            final String osVersion = ut.getOsVersion();
            final String appVersion = ut.getAppVersion();
            final String osType = ut.getOsType();
            final String phoneType = ut.getPhoneType();
            final String net = ut.getNet();
            final String applicationID = ut.getApplicationId(); // 应用ID
            //final String packageName = authHeader.get;
            //final long timestamp =   Long.valueOf(ut.getTmsi());
            final String longitude = ut.getLongitude();
            final String latitude =  ut.getLatitude();
            // 登录类型：0. 短信验证码登录
           // final int type = json.getIntValue("type");
            final String phone = json.getString("userPhone");
            final String hostIp = ut.getHost();
       /*     if (StringUtils.isBlank(authCode) || timestamp == 0) {
                log.warn("参数错误,type=" + type + "," + json);
                return StatusCode.PARAM_ERROR.toJSON("请输入验证码!");
            }*/
     /*       if (type != 0) {
                log.warn("param error,type:" + type);
                return StatusCode.PARAM_ERROR.json().msg("仅支持验证码登录。").toString();
            }*/

            if (user == null) {
                log.warn("用户:" + userId + " 未注册");
                return StatusCode.USER_NOT_FOUND.toJSON("您还未注册，请先注册。");
            }
            String result = null;
            // 测试号码
            if (ObjectUtils.isEqual("17092510264", phone) && ObjectUtils.isEqual("170414", authCode)) {

            } else {
                // 1校验验证码
                result = checkSmsCode(user.getUserId(), authCode,user.getDetailType()+"");
                if (result != null) {
                    return result;
                }
            }
            Merchant merchant = sdkAppDao.getMerchant(user.getMerchantId(), Constant.GetMemInfoTye.BYMERCHANTID);
            if (merchant == null) {
                log.warn("商户:" + merchant + " 未注册");
                return StatusCode.USER_NOT_FOUND.toJSON("您还未注册，请先注册。");
            }
            if (merchant.getSourceType() == Constant.SourceType.KAMENG) {
                log.warn("商户:" + merchant.getDealerId() + " 为卡盟商户");
                return StatusCode.USER_NOT_FOUND.toJSON("该号码不适用于远特时空！");
            }
            if (merchant.getFlag() == Constant.Flag.FLAG_REMOVE) {
                log.warn("商户已注销," + merchant);
                return StatusCode.USER_NOT_FOUND.toJSON("您所在商户已被注销，具体请联系管理员！");
            }
            // 黑名单控制
            Boolean blackFlag = userDAO.checkBlackUser(user.getUserId());
            if (blackFlag == null) {
                log.warn("查询黑名单返回null");
                return StatusCode.SYSTEM_EXCEPTION.toJSON();
            }
            if (blackFlag) {
                log.warn("黑名单用户,userid:" + user.getUserId());
                return StatusCode.USER_NOT_FOUND.toJSON("您已被加入黑名单，解封请联系管理员");
            }

            final long curTime = System.currentTimeMillis();
            user.setApplicationID(applicationID);
            user.setAppVersion(appVersion);
            user.setNet(net);
            user.setOsType(osType);
            user.setOsVersion(osVersion);
            user.setPhoneType(phoneType);
            //user.setPackageName(packageName);
            user.setTmsi(curTime);
            user.setLastTime(curTime);
            user.setHostIp(hostIp);
            user.setLatitude(latitude);
            user.setLongitude(longitude);

            boolean update = userDAO.updateUser(user);
            if (!update) {
                log.warn("更新客户端用户的信息失败");
                return StatusCode.SYSTEM_EXCEPTION.toJSON();
            }

            JSONObject dtJson = new JSONObject();
            dtJson.put("tmsi", String.valueOf(curTime));
            setInfo(user, merchant, dtJson);
            String appId = ut.getAppId();
            String livingCheckFlag = getLivingCheckFlagByAppId(appId);
            dtJson.put("livingCheckFlag",livingCheckFlag);
            return StatusCode.SUCCESS.json().data(dtJson).toString();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return StatusCode.SYSTEM_EXCEPTION.json().toString();
        }
    }

    private void setInfo(User user, Merchant merchant, JSONObject dtJson) {
        // 用户隐私协议签约时间
        String privacyTime = "";
        if (0L < merchant.getRegistTime()) {
            // 商户签订隐私协议时间
            MerchantDetailInfo info = userDAO.getMerchantDetail(user.getMerchantId());
            if (Objects.nonNull(info)) {
                privacyTime = Objects.isNull(info.getRatifyAccordTime()) ? ""
                        : Long.toString(info.getRatifyAccordTime());
            }
        }
        dtJson.put("privacyTime", privacyTime);
        String tableName = proConfDAO.getTableName(user.getDetailType());
        ProConf conf = proConfDAO.getConf(tableName);// 获取配置信息 不判断异常，情愿异常报错
        dtJson.put("withdrwaLimit", conf.getWithdrawMinFee() + "");
        dtJson.put("inviteCode", user.getInviteCode());
        dtJson.put("status", merchant.getYtskStatus() + "");
        dtJson.put("userName", user.getUserName());
        dtJson.put("userId", user.getUserId());
        dtJson.put("phone", user.getPhone());
        dtJson.put("defaultPayType", Constant.PayType.NONE + "");
        JSONArray payInfoList = new JSONArray();
        if (ObjectUtils.nonNullOrEmpty(user.getAlipayUserId())) {
            dtJson.put("defaultPayType", Constant.PayType.ALIPAY + "");
            addPayList(payInfoList, user.getAlipayUserId(), user.getAlipayUserName(), Constant.PayType.ALIPAY);
        }
        dtJson.put("payInfoList", payInfoList);

        /** 卡盟app相关参数 **/
        dtJson.put("cityCode", user.getCityCode());
        dtJson.put("cityName", user.getCityName());
        dtJson.put("attribute", merchant.getMerchant_attribute() + "");
        dtJson.put("attributeStatus", merchant.getAttribute_status() + "");
        /** 如果是游客账户，sign 2游客3审核中 **/
        String sign = merchant.getIsSignAgreement() + "";
        if (merchant.getStatus() != 0) {
            sign = "2";
            // if(3 == merchant.getStatus())
            // sign = "3";
        }
        /** 如果是游客账户，sign 2游客3审核中 **/
        dtJson.put("sign", sign);
        /** 卡盟app相关参数 **/
        addShqpInfo(merchant.getDealerId(), dtJson, merchant.getStatus());
        // 分享号码库权限
        setSellcardInfo(dtJson, merchant, conf);
    }

    private void setSellcardInfo(JSONObject dtJson, Merchant merchant, ProConf conf) {
        dtJson.put("merchantId", merchant.getMerchantId());
        dtJson.put("sellCardPower", 0);
        dtJson.put("sellcardUrl", "");
        final String sellCardPower = conf.getSellcardPower();
        if (ObjectUtils.nonNullOrEmpty(sellCardPower)) {
            if (sellCardPower.contains(String.valueOf(merchant.getYtskStatus()))) {
                dtJson.put("sellCardPower", 1);
            } else {
                dtJson.put("sellCardPower", 2);
            }
            dtJson.put("sellcardUrl", conf.getSellcardUrl() + merchant.getMerchantId());
        }
    }

    /**
     * 获取授权牌信息
     **/
    protected void addShqpInfo(String dealerId, JSONObject dataJson, int kmStatus) {
        JSONObject shqpInfoJso = new JSONObject();
        dataJson.put("shqp", shqpInfoJso);
        shqpInfoJso.put("endDate", "0");
        shqpInfoJso.put("url", "");
        shqpInfoJso.put("state", "0");
        shqpInfoJso.put("renewStr", "");
        // 游客直接返回
        if (kmStatus != 0) {
            return;
        }
        ShqpInfo shqpInfo = sdkAppDao.getShqpInfo(dealerId);
        if (shqpInfo == null || shqpInfo.getShqpEndTime() == 0) {
            return;
        }
        if (ObjectUtils.isNullOrEmpty(shqpInfo.getShqpUrl())) {
            // 去ums生成授权牌
            String res = HTTPUtils.sendPost(Constant.URLS.UMS + "/s/user/shqpInfo",
                    String.format("{\"dealerId\":\"%s\"}", dealerId));
            log.info(String.format("授权牌生成，url:【%s】,dealerId【%s】,res【%s】", Constant.URLS.UMS + "/s/user/shqpInfo",
                    dealerId, res));
            if (ObjectUtils.isNullOrEmpty(res)) {
                log.error("获取授权牌信息失败，" + dealerId);
                return;
            }
            JSONObject resJso = JSONObject.parseObject(res);
            if (ObjectUtils.nonEqual(resJso.getString("code"), "200")) {
                return;
            }
            dataJson.put("shqpInfo", resJso.getJSONObject("data"));
            return;
        }
        int nowDate = Integer.parseInt(DateUtils.format(Clock.systemDefaultZone().millis(), "yyyyMMdd"));
        int endDate = shqpInfo.getShqpEndTime();
        int twoMonAgo = Integer.parseInt(DateUtils.getExpectDate(endDate + "", 0, -2, 0, "yyyyMMdd"));
        final String endDateStr = endDate + "";
        final String year = endDateStr.substring(0, 4);
        final String month = endDateStr.substring(4, 6);
        final String day = endDateStr.substring(6, 8);

        String state, renewStr;
        if (nowDate <= twoMonAgo) {
            state = "1";
            renewStr = "";
        } else if (nowDate > twoMonAgo && nowDate <= endDate) {
            state = "2";
            renewStr = new StringBuilder("温馨提示：您的授权牌将在").append(year).append("年").append(month).append("月").append(day)
                    .append("日到期，请尽快签名并点击下方“授权牌续约”。").append("续约后授权牌有效期限为申请授权牌续约日起有效期一年。").toString();
        } else {
            state = "3";
            renewStr = new StringBuilder("温馨提示：您的授权牌在").append(year).append("年").append(month).append("月").append(day)
                    .append("日已到期，请尽快签名并点击下方“授权牌续约”。").append("续约后授权牌有效期限为申请授权牌续约日起有效期一年。").toString();
        }

        shqpInfoJso.put("endDate", year + "-" + month + "-" + day);
        shqpInfoJso.put("url", AliOSSUtil.generatePresignedUrl(shqpInfo.getShqpUrl()));
        shqpInfoJso.put("state", state);
        shqpInfoJso.put("renewStr", renewStr);
    }

    private void addPayList(JSONArray arr, String payId, String payName, int payType) {
        JSONObject each = new JSONObject();
        each.put("payType", payType + "");
        each.put("payId", payId);
        each.put("payName", payName);
        arr.add(each);
    }

    private String kamengLogin(JSONObject json) {
        // Deprecated 兼容老版本
        final String userId = json.containsKey("userId") ? json.getString("userId") : "";
        final String authCode = json.getString("authCode");
        final String osVersion = json.getString("osVersion");
        final String appVersion = json.getString("appVersion");
        final String osType = json.getString("osType");
        final String phoneType = json.getString("phoneType");
        final String net = json.getString("net");
        final String applicationID = json.getString("applicationID"); // 应用ID
        final String packageName = json.getString("packageName");
        final long timestamp = json.getLongValue("timestamp");
        // 登录类型：0. 短信验证码登录
        final String type = json.containsKey("type") ? json.getString("type") : "";
        final String phone = json.containsKey("userPhone") ? json.getString("userPhone") : "";
        final String token = json.getString("token");
        System.out.println(json.getString("boryaAuth"));
        final String boryaAuthStr = json.getString("boryaAuth");
        final String hostIp = json.getString("hostIp");
        HeaderEntity authHeader = JSONObject.parseObject(boryaAuthStr, HeaderEntity.class);

        final String key = userId.trim().length() == 0 ? json.getString("userPhone") : userId;
        String decryptToken;// = EncryptUtils.decrypt(key,
        // timestamp,packageName, token);
        if (Objects.nonNull(authHeader) && "1".equals(authHeader.getAppType())) {
            if (1 == authHeader.getOsType()) {// ios
                if (authHeader.getAppVersion() < 2019042500) {
                    return StatusCode.UPGRADE.toJSON();
                }
                if (authHeader.getAppVersion() < 2019051600) {
                    decryptToken = EncryptUtils.decrypt(key, timestamp, packageName, token);
                } else {
                    decryptToken = EncryptUtils.decryptNew(key, timestamp, packageName, token);
                }
            } else if (2 == authHeader.getOsType()) {// android
                if (authHeader.getAppVersion() < 2019051600) {
                    decryptToken = EncryptUtils.decrypt(key, timestamp, packageName, token);
                } else {
                    decryptToken = EncryptUtils.decryptNew(key, timestamp, packageName, token);
                }
            } else {
                log.error("请求头osType错误" + authHeader);
                return StatusCode.PARAM_ERROR.toJSON("");
            }
        } else {
            decryptToken = EncryptUtils.decrypt(key, timestamp, packageName, token);
        }

        if (StringUtils.isBlank(authCode) || timestamp == 0) {
            log.warn("参数错误,type=" + type + "," + json);
            return StatusCode.PARAM_ERROR.toJSON("请输入验证码!");
        }

        if (decryptToken == null || decryptToken.trim().length() == 0) {
            log.warn("参数错误,token decrypt error,token=" + token + "," + json);
            return StatusCode.PARAM_ERROR.toJSON("请求错误");
        }
        final String[] tokens = decryptToken.split(",", -1);
        if (tokens == null || tokens.length < 6) {
            log.warn("[" + hostIp + "] Illegal token,token=" + token);
            return StatusCode.FORBID.toJSON("TOken解析错误");
        }

        final String longitude = tokens.length > 7 ? tokens[7].trim() : "0";
        final String latitude = tokens.length > 8 ? tokens[8].trim() : "0";

        User user = null;
        if (phone.trim().length() > 0) {
            user = userDAO.getUserByPhone(phone);
        } else if (userId.trim().length() > 0) {
            user = userDAO.getUser(userId);
        }

        if (user == null) {
            log.warn("用户:" + userId + " 未注册");
            return StatusCode.USER_NOT_FOUND.toJSON("您还未注册，请点击“创建账号”快来注册！");
        }

        if (user.getFlag() == com.borya.model.db.Flag.DELETED) {
            log.warn("用户:" + userId + " 被删除");
            return StatusCode.USER_NOT_FOUND.toJSON("您还未注册，请点击“创建账号”快来注册！");
        }

        Merchant merchant = userDAO.getMerchant(user.getDealerId());
        String result = processFlag(merchant);
        if (result != null) {
            return result;
        }
        Boolean blackFlag = userDAO.checkBlackUser(user.getUserId());
        if (blackFlag == null) {
            log.warn("查询黑名单返回null");
            return StatusCode.SYSTEM_EXCEPTION.toJSON();
        }
        if (blackFlag) {
            log.warn("黑名单用户,userid:" + user.getUserId());
            return StatusCode.USER_NOT_FOUND.toJSON("您已被加入黑名单，解封请联系管理员");
        }
        if (user.getSourceType() == 2) {
            // 远特时空用户
            log.warn("用户:" + userId + " 为远特时空用户");
            return StatusCode.USER_NOT_FOUND.toJSON("该号码非卡盟账号！");
        }

        /** TODO IOS 审核测试账号 **/
        if ("17092510264".equals(user.getUserId()) && "170414".equals(authCode)) {
            log.info("[CHECK] :" + json);
        } else {
            // 验证码验证
            result = checkSmsCode(user.getUserId(), authCode,user.getDetailType()+"");
            if (result != null) {
                return result;
            }
        }

        final long curTime = System.currentTimeMillis();
        user.setApplicationID(applicationID);
        user.setAppVersion(appVersion);
        user.setNet(net);
        user.setOsType(osType);
        user.setOsVersion(osVersion);
        user.setPhoneType(phoneType);
        user.setPackageName(packageName);
        user.setTmsi(curTime);
        user.setLastTime(curTime);
        user.setHostIp(hostIp);
        user.setLatitude(latitude);
        user.setLongitude(longitude);
        // 3.登录成功后，更新用户登录信息，
        boolean update = userDAO.updateUser(user);

        if (!update) {
            log.warn("更新客户端用户的信息失败");
            return StatusCode.SYSTEM_EXCEPTION.toJSON();
        }

        // //4.登录记录表存入登录信息,记录用户登录次数
        // String result = saveAllLoginData(userId, osVersion, appVersion,
        // osType, phoneType, net,
        // applicationID, packagename, curTime);
        // if(!result.equals("OK")) {
        // return result;
        // }

        /** 如果是游客账户，sign 2游客3审核中 **/
        String sign = String.valueOf(merchant.getIsSignAgreement());
        if (merchant.getStatus() != 0) {
            sign = "2";
            // if(3 == merchant.getStatus())
            // sign = "3";
        }
        /** 如果是游客账户，sign 2游客3审核中 **/
        JSONObject dtJson = new JSONObject();
        dtJson.put("tmsi", String.valueOf(curTime));
        dtJson.put("cityCode", user.getCityCode());
        dtJson.put("cityName", user.getCityName());
        dtJson.put("inviteCode", user.getInviteCode());
        dtJson.put("userName", user.getUserName());
        dtJson.put("sign", sign);
        dtJson.put("leftFee", user.getLeftFee());
        dtJson.put("userId", user.getUserId());
        dtJson.put("attribute", String.valueOf(merchant.getMerchant_attribute()));
        dtJson.put("attributeStatus", String.valueOf(merchant.getAttribute_status()));
        return StatusCode.SUCCESS.toDiyJson(true, "data", dtJson.toJSONString());

    }

    private String checkSmsCode(final String userId, String authCode,String detailType) {
        final long curTime = System.currentTimeMillis();
        SmsInfo smsInfo = SMC_CODE_MAP.get(detailType + userId);
        if (smsInfo == null) {
            log.warn(userId + "的短信内容不存在");
            return StatusCode.CAPTCHE_NOT_FOUND.toJSON("验证码已失效，请重新获取");
        } else {
            int useNum = smsInfo.getUseNum() + 1;
            smsInfo.setUseNum(useNum);
            SMC_CODE_MAP.put(detailType + userId, smsInfo);
            if (useNum >= 1 && useNum <= 3) {
                String authCode2 = smsInfo.getAuthCode();
                if (!authCode.equals(authCode2) && smsInfo.getTimeoutTime() > curTime) { // 验证码错误，但是没有超时
                    log.warn("验证码错误.用户上传的验证码：【" + authCode + "】，平台保存的验证码：【" + authCode2 + "】");
                    return StatusCode.CAPTCHE_NOT_FOUND.toJSON("验证码错误，请重新输入");
                } else if (smsInfo.getTimeoutTime() < curTime) { // 验证码正确，但超时
                    log.warn("用户获取验证码到校验验证码超时");
                    return StatusCode.CAPTCHE_NOT_FOUND.toJSON("校验验证码超时，请重新获取验证码");
                } else {
                    // success
                    return null;
                }
            } else {
                SMC_CODE_MAP.remove(detailType + userId);
                return StatusCode.CAPTCHE_NOT_FOUND.toJSON("验证码已失效，请重新获取验证码");
            }
        }
    }
}
